﻿#include<iostream>
#include<cmath>
#include<windows.h>
#include<immintrin.h>
//#include<arm_neon.h>
using namespace std;
const int SIZ = 400;
const int TIM = 10000000;

float sum(float* array, int n)
{
    float sum = 0;
    for (int i = 0; i < n; i += 1)
    {
        sum += array[i];
    }
    return sum;
}
void add(float* array, int n, float bonus)
{
    /*for (int i = 0; i < n; i += 1)
    {
        array[i] += bonus;
    }*/
    __m128 f1, f2;
    f1 = _mm_set_ps(bonus,bonus,bonus,bonus);//f1 = _mm_set1_ps(bonus);
    for (int i = 0; i < n; i += 4)
    {
        f2 = _mm_loadu_ps(array + i); //从(array+i)读取连续的4个单精度浮点数
        f2 = _mm_add_ps(f1, f2); // 两个向量的4个单精度浮点数对位相加
        _mm_store_ps(array + i, f2);// 将向量f2，保存在地址(matrix+k)处
    }
}
void splUCB(float* rst, float* thisreward, float* thisNi, float cst, float ttlN, float* thisOi, int iscale)//平凡串行算法
{
    for (int i = 0; i < iscale; i += 1)
    {
        rst[i] = thisreward[i] / thisNi[i] + cst * sqrt(log(ttlN) / (thisNi[i] + thisOi[i]));
        //printf("%d:")
    }
}
void UCB(float* rst, float* thisreward, float* thisNi, float cst, float ttlN, float* thisOi, int iscale)//SIMD并发算法
{
    __m128 trwd, cs, medi;
    __m128 ttN, tNi[SIZ], tOi;
    float sqr[SIZ]; 
    ttN = _mm_set1_ps(log(ttlN));
    cs = _mm_set1_ps(cst);
    for (int i = 0; i < iscale; i += 4)
    {
        tNi[i] = _mm_loadu_ps(thisNi + i);//记忆性
        tOi = _mm_loadu_ps(thisOi + i);//从(array+i)读取连续的4个单精度浮点数
        tOi = _mm_add_ps(tOi, tNi[i]);//加法
        tOi = _mm_div_ps(ttN, tOi);//除法//保存着用于开方的珍贵数据
        _mm_store_ps(sqr + i, tOi);// 将向量tOi，保存在地址(sqr+i)处
        for (int j = 0; j < 4; j += 1)
        {
            sqr[i + j] = sqrt(sqr[i + j]);
        }
    }
    for (int i = 0; i < iscale; i += 4)
    {
        trwd = _mm_loadu_ps(thisreward + i);
        trwd = _mm_div_ps(trwd, tNi[i]);//加数1
        medi = _mm_loadu_ps(sqr + i);
        medi = _mm_mul_ps(medi, cs);//加数2
        medi = _mm_add_ps(medi, trwd);
        _mm_store_ps(rst + i, medi);
    }
}

int main()
{
    long long head, mid, end, freq;
    long long t1, t2;
    QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
    
    
    const int scale = 12;
    float rst[scale];
    float RW[scale] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    float Ni[scale] = { 2,2,2,2,2,2,2,2,2,2,2,2 };
    float c = 1, N = 10;
    float Oi[scale] = { 0,1,0,1,0,1,0,1,0,1,0,1 };
    QueryPerformanceCounter((LARGE_INTEGER*)&head);
    for (int i = 0; i < TIM; i += 1)
    {
        splUCB(rst, RW, Ni, c, N, Oi, scale);
    }
    QueryPerformanceCounter((LARGE_INTEGER*)&mid);
    /*for (int i = 0; i < scale; i += 1)
    {
        cout << rst[i] << ' ';
    }
    cout << '\n';*/
    for (int i = 0; i < TIM; i += 1)
    {
        UCB(rst, RW, Ni, c, N, Oi, scale);
    }
    QueryPerformanceCounter((LARGE_INTEGER*)&end);
    cout << "平凡算法时间/us：" << (mid - head) * 1000000 / freq
        << "\nSIMD算法时间/us：" << (end - mid) * 1000000 / freq
        << "\n并发加速比：" << (end - mid)* 100 / (mid - head)  << '%';
    /*for (int i = 0; i < scale; i += 1)
    {
        cout << rst[i] << ' ';
    }*/
	return 0;
}





/*
* 常用指令x86
//数据类型
__m128//float
__m128d// double
__m128i//integer
//load：
_mm_load_ps(float ∗p) //将从内存中地址p开始的4个float数据加载到寄存器中，要求p的地址是16字节对齐
_mm_loadu_ps(float ∗p)//类似_mm_load_ps但是不要求地址是16字节对齐
//set:
_mm_set_ps(float a,float b,float c,float d) //将a,b,c,d赋值给寄存器
//store：
_mm_store_ps(float ∗p, _m128 a) //将寄存器a的值存储到内存p中
//数据计算：
_mm_add_ps //加法
_mm_mul_ps //乘法
_mm_sub_ps //减法
_mm_div_ps //除法

*/

/*
* 常用指令arm
////数据类型
//float32_t, , float32x4_t, float64x2_t, float32x4x2_t...
//int8_t, int8x16_t, int16x8_t, int32x4_t, int64x2_t, int8x16x2_t...

//load：以float为例
float32x2_t vld1_f32(float32_t const ∗ptr); //读取连续2个单精度浮点数到向量寄存器
float32x4_t vld1q_f32(float32_t const ∗ptr); //读取连续4个单精度浮点数到向量寄存器
float32x4x2_t vld2q_f32(float32_t const ∗ptr); //读取连续8个单精度浮点数到2个向量寄存器
//store:
void vst1q_s32(int32_t ∗ ptr, int32x4_t val); //将向量元素保存为连续4个32位整数数
void vst1q_u32(uint32_t ∗ ptr, uint32x4_t val);
//将向量元素保存为连续4个32位无符号整数数
void vst1q_f32(float32_t ∗ ptr, float32x4_t val);
//将向量元素保存为连续4个单精度浮点数数
// 
//move
int32x2_t vget_high_s32(int32x4_t a); //将a高位的两个元素复制到另一个向量寄存器
float32x2_t vget_low_f32(float32x4_t a); //将a低位的两个元素复制到另一个向量寄存器
float32_t vget_lane_f32(float32x2_t v, const int lane); //获得向量v第lane个通道的元素
float32_t vgetq_lane_f32(float32x4_t v, const int lane); //获得向量v第lane个通道的元素
float32x2_t vset_lane_f32(float32_t a, float32x2_t v, const int lane); //设置向量v第lane个通道的元素的值为a
float32x4_t vsetq_lane_f32(float32_t a, float32x4_t v, const int lane); ////设置向量v第lane个通道的元素的值为a
//arithmetic
float32x4_t vaddq_f32(float32x4_t a, float32x4_t b); //对位加法
float32x4_t vmulq_f32(float32x4_t a, float32x4_t b); //对位乘法
float32x4_t vsubq_f32(float32x4_t a, float32x4_t b); //对位减法
float32x4_t vdivq_f32(float32x4_t a, float32x4_t b); //对位除法
*/

